import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import openpyxl
import os
from datetime import datetime
import ctypes

class KMLPathGenerator:
    def __init__(self, root):
        self.root = root
        self.root.title("")
        self.root.geometry("660x560")
        self.root.resizable(True, True)

        # 设置中文字体支持
        self.style = ttk.Style()
        self.style.configure("TLabel", font=("SimHei", 10))
        self.style.configure("TButton", font=("SimHei", 10))
        self.style.configure("TRadiobutton", font=("SimHei", 10))

        # #避免字体模糊
        # # 告诉操作系统使用程序自身的dpi适配
        # ctypes.windll.shcore.SetProcessDpiAwareness(1)
        # # 获取屏幕的缩放因子
        # ScaleFactor = ctypes.windll.shcore.GetScaleFactorForDevice(0)
        # # 设置程序缩放
        # self.root.tk.call('tk', 'scaling', ScaleFactor / 75)

        # 数据存储
        self.excel_data = []
        self.selected_file = ""

        self.create_widgets()

    def create_widgets(self):
        # 标题标签
        title_frame = ttk.Frame(self.root, padding=10)
        title_frame.pack(fill=tk.X)

        title_label = ttk.Label(title_frame, text="输电KML文件生成工具_V1.2",
                                font=("SimHei", 16, "bold"))
        title_label.pack()

        # 文件选择区域
        file_frame = ttk.Frame(self.root, padding=10)
        file_frame.pack(fill=tk.X)

        ttk.Label(file_frame, text="坐标文件:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)

        self.file_entry = ttk.Entry(file_frame, width=40)
        self.file_entry.grid(row=0, column=1, padx=5, pady=5)

        browse_btn = ttk.Button(file_frame, text="浏览", command=self.browse_file)
        browse_btn.grid(row=0, column=2, padx=5, pady=5)

        # 选项区域
        options_frame = ttk.LabelFrame(self.root, text="生成选项", padding=4)
        options_frame.pack(fill=tk.X, padx=4, pady=4)

        # 排序选项
        sort_frame = ttk.Frame(options_frame)
        sort_frame.pack(fill=tk.X, pady=5)

        ttk.Label(sort_frame, text="排序选项:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)

        self.sort_var = tk.IntVar(value=1)  # 默认选中自动排序

        auto_sort_radio = ttk.Radiobutton(sort_frame, text="自动排序",
                                          variable=self.sort_var, value=1)
        auto_sort_radio.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)

        no_sort_radio = ttk.Radiobutton(sort_frame, text="不排序",
                                        variable=self.sort_var, value=0)
        no_sort_radio.grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)

        # 生成类型选项
        type_frame = ttk.Frame(options_frame)
        type_frame.pack(fill=tk.X, pady=5)

        ttk.Label(type_frame, text="生成类型:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)

        self.generate_type = tk.IntVar(value=2)  # 默认选中路径

        point_radio = ttk.Radiobutton(type_frame, text="点",
                                      variable=self.generate_type, value=1)
        point_radio.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)

        path_radio = ttk.Radiobutton(type_frame, text="路径",
                                     variable=self.generate_type, value=2)
        path_radio.grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)

        # 按线路名称分割选项
        split_frame = ttk.Frame(options_frame)
        split_frame.pack(fill=tk.X, pady=5)

        ttk.Label(split_frame, text="文件分割:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)

        self.split_by_line = tk.BooleanVar(value=False)  # 默认不分割

        split_check = ttk.Checkbutton(split_frame, text="按线路名称分割为多文件",
                                      variable=self.split_by_line)
        split_check.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)

        # 生成按钮
        button_frame = ttk.Frame(self.root, padding=10)
        button_frame.pack(fill=tk.X)

        generate_btn = ttk.Button(button_frame, text="开始生成",
                                  command=self.generate_kml, style='Accent.TButton')
        generate_btn.pack(pady=10)

        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(self.root, variable=self.progress_var,
                                            maximum=100, mode='determinate')
        self.progress_bar.pack(fill=tk.X, padx=10, pady=5)

        # 提示信息区域
        info_frame = ttk.LabelFrame(self.root, text="使用提示", padding=4)
        info_frame.pack(fill=tk.BOTH, expand=True, padx=4, pady=4)

        info_text = """1.坐标XLSX文件的标题行须包含“线路名称”、“电压等级”、“杆塔号”、“经度”、“纬度”；“备注”列可选。
2.所有杆塔的信息应按运行杆塔填写完整，不留空行。
3.经度、纬度单元格应为常规或数值格式。
4.支线应包含#000的数据行。"""

        info_label = ttk.Label(info_frame, text=info_text, justify=tk.LEFT, wraplength=600)
        info_label.pack(fill=tk.BOTH, expand=True)

        # 状态栏
        status_frame = ttk.Frame(self.root)
        status_frame.pack(fill=tk.X, side=tk.BOTTOM)

        self.status_var = tk.StringVar()
        self.status_var.set("就绪")
        status_bar = ttk.Label(status_frame, textvariable=self.status_var,
                               relief=tk.SUNKEN, anchor=tk.W, width=36)
        status_bar.pack(side=tk.LEFT, fill=tk.X, expand=True)

        # 版权信息
        copyright_label = ttk.Label(status_frame, text="株洲输检_2025,Daoban",
                                    font=("SimHei", 10), foreground="#888888")
        copyright_label.pack(side=tk.RIGHT, padx=10, pady=5)

    def browse_file(self):
        file_path = filedialog.askopenfilename(
            filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")]
        )
        if file_path:
            self.selected_file = file_path
            self.file_entry.delete(0, tk.END)
            self.file_entry.insert(0, os.path.basename(file_path))
            self.status_var.set(f"已选择文件: {os.path.basename(file_path)}")

    def read_excel_file(self):
        if not self.selected_file:
            messagebox.showerror("错误", "请先选择一个XLSX文件")
            return False

        try:
            self.status_var.set("正在读取文件...")
            self.root.update()

            workbook = openpyxl.load_workbook(self.selected_file, read_only=True)
            sheet = workbook.active

            # 查找表头行
            header_row = None
            for row in sheet.iter_rows(min_row=1, max_row=10, values_only=True):
                if row and all(cell is not None for cell in row[:5]):
                    header_row = row
                    break

            if not header_row:
                messagebox.showerror("错误", "无法找到有效的表头")
                return False

            # 查找所需列的索引
            required_columns = ["线路名称", "电压等级", "杆塔号", "经度", "纬度"]
            column_indices = {}

            for col_name in required_columns:
                try:
                    column_indices[col_name] = header_row.index(col_name)
                except ValueError:
                    messagebox.showerror("错误", f"找不到列: {col_name}")
                    return False

            # 查找备注列（可选）
            remark_index = None
            for i, col_name in enumerate(header_row):
                if col_name and "备注" in str(col_name):
                    remark_index = i
                    break

            # 读取数据行
            self.excel_data = []
            total_rows = sheet.max_row
            current_row = 0

            for row in sheet.iter_rows(min_row=2, values_only=True):
                current_row += 1
                if current_row % 100 == 0:
                    self.progress_var.set(current_row / total_rows * 100)
                    self.root.update()

                # 过滤掉经度或纬度为空或为0的行
                if not all([isinstance(row[column_indices["经度"]], (int, float)) and row[column_indices["经度"]] != 0,
                            isinstance(row[column_indices["纬度"]], (int, float)) and row[
                                column_indices["纬度"]] != 0]):
                    continue

                try:
                    line_data = {
                        "线路名称": row[column_indices["线路名称"]],
                        "电压等级": self._normalize_voltage(row[column_indices["电压等级"]]),
                        "杆塔号": row[column_indices["杆塔号"]],
                        "经度": float(row[column_indices["经度"]]),
                        "纬度": float(row[column_indices["纬度"]]),
                        "备注": row[remark_index] if remark_index is not None else ""
                    }
                    self.excel_data.append(line_data)
                except (ValueError, IndexError) as e:
                    print(f"处理行 {current_row} 时出错: {e}")
                    continue

            if not self.excel_data:
                messagebox.showerror("错误", "文件中没有找到有效数据")
                return False

            self.status_var.set(f"已读取 {len(self.excel_data)} 条记录")
            return True

        except Exception as e:
            messagebox.showerror("错误", f"读取文件时出错: {str(e)}")
            return False

    def _normalize_voltage(self, voltage_str):
        """标准化电压等级字符串，提取数值部分"""
        if isinstance(voltage_str, int) or isinstance(voltage_str, float):
            return voltage_str

        if not isinstance(voltage_str, str):
            return 0

        # 去除kV、KV、千伏等单位
        voltage_str = voltage_str.strip().replace('kV', '').replace('KV', '').replace('千伏', '')

        try:
            return float(voltage_str)
        except ValueError:
            return 0

    def generate_kml(self):
        if not self.read_excel_file():
            return

        self.status_var.set("正在生成KML文件...")
        self.root.update()

        # 根据选择决定是否排序
        if self.sort_var.get() == 1:
            self.excel_data.sort(
                key=lambda x: (-x["电压等级"], x["线路名称"], x["杆塔号"])
            )
            self.status_var.set("数据已排序")
        else:
            self.status_var.set("使用原始数据顺序")

        # 根据选择决定生成点还是路径
        if self.generate_type.get() == 1:
            if self.split_by_line.get():
                self.create_split_point_kml()
            else:
                kml_content = self.create_point_kml()
                self.save_single_kml(kml_content, "点")
        else:
            if self.split_by_line.get():
                self.create_split_path_kml()
            else:
                kml_content = self.create_path_kml()
                self.save_single_kml(kml_content, "路径")

    def save_single_kml(self, kml_content, type_name):
        # 保存单个KML文件
        default_filename = f"线路{type_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.kml"
        save_path = filedialog.asksaveasfilename(
            defaultextension=".kml",
            filetypes=[("KML files", "*.kml"), ("All files", "*.*")],
            initialfile=default_filename
        )

        if save_path:
            try:
                with open(save_path, 'w', encoding='utf-8') as f:
                    f.write(kml_content)
                messagebox.showinfo("成功", f"KML文件已成功生成并保存到:\n{save_path}")
                self.status_var.set("KML生成完成")
            except Exception as e:
                messagebox.showerror("错误", f"保存文件时出错: {str(e)}")
                self.status_var.set("保存文件失败")
        else:
            self.status_var.set("KML生成已取消")

    def create_point_kml(self, points=None):
        """创建点的KML文档"""
        if points is None:
            points = self.excel_data

        # 创建点的KML文档
        kml_header = """<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
    <name>线路杆塔点</name>
    <description>输电KML文件生成工具_V1.0</description>
"""

        kml_body = ""

        # 遍历数据生成点
        total_points = len(points)
        for i, point in enumerate(points):
            if i % 100 == 0:
                self.progress_var.set(i / total_points * 100)
                self.root.update()

            # 构建描述信息，包含备注（如果有）
            description = f"电压等级: {point['电压等级']}kV，"
            if point.get("备注"):
                description += f"{point['备注']}"

            kml_body += f"""
    <Placemark>
        <name>{point["线路名称"]}:{point["杆塔号"]}</name>
        <description>{description}</description>
        <Point>
            <coordinates>{point["经度"]},{point["纬度"]},0</coordinates>
        </Point>
    </Placemark>
"""

        kml_footer = """
</Document>
</kml>
"""

        return kml_header + kml_body + kml_footer

    def create_path_kml(self, points=None):
        """创建路径的KML文档"""
        if points is None:
            points = self.excel_data

        # 创建路径的KML文档
        kml_header = """<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
    <name>多线路路径</name>
    <description>输电KML文件生成工具_V1.0</description>
"""

        kml_body = ""

        # 根据电压等级获取颜色
        def get_color(voltage):
            # 220kV: 紫色 (ff800080)
            if voltage == 220:
                return "ff800080"
            # 110kV: 朱色 (ff004080)
            elif voltage == 110:
                return "ff5541f0"
            # 35kV: 鲜黄色 (ff00ffff)
            elif voltage == 35:
                return "ff00ffff"
            # 其他: 白色 (ffffffff)
            else:
                return "ffffffff"

        # 遍历数据生成线段
        total_points = len(points)
        for i in range(1, total_points):
            if i % 100 == 0:
                self.progress_var.set(i / total_points * 100)
                self.root.update()

            prev_point = points[i - 1]
            current_point = points[i]

            if prev_point["线路名称"] == current_point["线路名称"]:
                voltage = prev_point["电压等级"]
                color = get_color(voltage)

                # 构建描述信息，包含备注（如果有）
                description = f"{voltage}kV；"
                if current_point.get("备注"):
                    description += f" {current_point['备注']}"

                kml_body += f"""
    <Placemark>
        <name>{prev_point["线路名称"]}:{prev_point["杆塔号"]}-{current_point["杆塔号"]}</name>
        <description>{description}</description>
        <Style>
            <LineStyle>
                <color>{color}</color>
                <width>3</width>
            </LineStyle>
        </Style>
        <LineString>
            <extrude>1</extrude>
            <tessellate>1</tessellate>
            <coordinates>
                {prev_point["经度"]},{prev_point["纬度"]},0
                {current_point["经度"]},{current_point["纬度"]},0
            </coordinates>
        </LineString>
    </Placemark>
"""

        kml_footer = """
</Document>
</kml>
"""

        return kml_header + kml_body + kml_footer

    def create_split_point_kml(self):
        """按线路名称分割，生成多个点文件"""
        # 按线路名称分组
        line_groups = {}
        for point in self.excel_data:
            line_name = point["线路名称"]
            if line_name not in line_groups:
                line_groups[line_name] = []
            line_groups[line_name].append(point)

        # 选择保存目录
        save_dir = filedialog.askdirectory(title="选择保存目录")
        if not save_dir:
            self.status_var.set("保存已取消")
            return

        # 为每个线路名称生成一个KML文件
        total_groups = len(line_groups)
        for i, (line_name, points) in enumerate(line_groups.items()):
            self.progress_var.set(i / total_groups * 100)
            self.root.update()

            kml_content = self.create_point_kml(points)
            filename = f"{line_name}_点_{datetime.now().strftime('%Y%m%d_%H%M%S')}.kml"
            filepath = os.path.join(save_dir, filename)

            try:
                with open(filepath, 'w', encoding='utf-8') as f:
                    f.write(kml_content)
            except Exception as e:
                messagebox.showerror("错误", f"保存文件 '{filename}' 时出错: {str(e)}")

        messagebox.showinfo("成功", f"已成功生成 {total_groups} 个KML文件到:\n{save_dir}")
        self.status_var.set(f"KML生成完成，共 {total_groups} 个文件")

    def create_split_path_kml(self):
        """按线路名称分割，生成多个路径文件"""
        # 选择保存目录
        save_dir = filedialog.askdirectory(title="选择保存目录")
        if not save_dir:
            self.status_var.set("保存已取消")
            return

        # 找出所有不同的线路名称
        line_names = set(point["线路名称"] for point in self.excel_data)

        # 为每个线路名称生成一个KML文件
        total_lines = len(line_names)
        file_count = 0

        for i, line_name in enumerate(line_names):
            self.progress_var.set(i / total_lines * 100)
            self.root.update()

            # 找出该线路名称的所有点
            line_points = [point for point in self.excel_data if point["线路名称"] == line_name]

            if len(line_points) < 2:
                continue  # 至少需要两个点才能形成线段

            # 生成KML内容
            kml_content = self.create_path_kml(line_points)

            # 保存文件
            filename = f"{line_name}_路径_{datetime.now().strftime('%Y%m%d_%H%M%S')}.kml"
            filepath = os.path.join(save_dir, filename)

            try:
                with open(filepath, 'w', encoding='utf-8') as f:
                    f.write(kml_content)
                file_count += 1
            except Exception as e:
                messagebox.showerror("错误", f"保存文件 '{filename}' 时出错: {str(e)}")

        messagebox.showinfo("成功", f"已成功生成 {file_count} 个KML文件到:\n{save_dir}")
        self.status_var.set(f"KML生成完成，共 {file_count} 个文件")


if __name__ == "__main__":
    root = tk.Tk()
    app = KMLPathGenerator(root)

    # 确保中文正常显示
    try:
        root.option_add("*Font", "SimHei 10")
    except:
        pass

    root.mainloop()